// GraphicsScene.cpp
//
#include "GLGraphicsScene.h"
#include "GLGraphicsView.h"

#include "UserInteractionManager.h"
#include "Settings.h"

#include "OpenGL/OpenGL.h"
#include "OpenGL/Renderer.h"

#include <QPainter>
#include <QKeyEvent>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneWheelEvent>
#include <QGraphicsSceneContextMenuEvent>

#include "MemCheck.h"

using namespace QtFwk;

// -----------------------------------------------------------------------------------------------
GLGraphicsScene::GLGraphicsScene( QWidget *parent )
: QGraphicsScene(parent)
{
	renderer  = new OpenGL::Renderer;
	uim	      = new UserInteractionManager;
	view	  = parent;
	zoomMode  = Settings::ZoomOnMouse;
	updating  = false;

	setSceneRect( parent->rect() );

	connect( this,SIGNAL(sceneRectChanged(const QRectF&)),SLOT(onResize(const QRectF&)) );
}

// -----------------------------------------------------------------------------------------------
GLGraphicsScene::~GLGraphicsScene()
{
	delete renderer;
	delete uim;
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::setZoomMode( Settings::ZoomMode zm )
{
	zoomMode = zm;
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::translateScene()
{
	makeCurrent();
	
	MouseStatus ms = uim->mouseStatus();

	OpenGL::Math::dvec2 curr ( renderer->convertWindowTo2D( ms.currPos().x(), ms.currPos().y() ) );
	OpenGL::Math::dvec2 prev ( renderer->convertWindowTo2D( ms.prevPos().x(), ms.prevPos().y() ) );

	if( false )
		std::cout<<"Mouse at " << curr.x << " "<< curr.y << std::endl;

	OpenGL::Math::dvec2 diff = curr-prev;
	OpenGL::Math::dvec3 newcenter = renderer->center() - OpenGL::Math::dvec3( diff[0],diff[1], 0.0 );

	renderer->setCenter( newcenter );

	
	updateDrawables();
	invalidate();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::zoomScene()
{
	makeCurrent();

	MouseStatus mouseStatus = uim->mouseStatus();

	// get the center of the scene
	OpenGL::Math::dvec3 target( renderer->center() );
	
	if( zoomMode == Settings::ZoomOnMouse )
	{
		// override center with mouse position
		OpenGL::Math::dvec2 curr = renderer->convertWindowTo2D( mouseStatus.currPos().x(), mouseStatus.currPos().y() ) ;

		target = OpenGL::Math::dvec3(curr,target.z);
	}

	double z     = mouseStatus.wheel() ;
	
	renderer->zoomInOut( z, target );
	updateDrawables();
	invalidate();
}
// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::updateDrawables()
{}


// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onResize( const QRectF & rect )
{
	makeCurrent();

	renderer->setViewport( 0,0,rect.width(), rect.height() );	

	resizeScene( rect.width(), rect.height() );
	updateDrawables();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::resizeScene( int w, int h)
{}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::trackMousePosition( const QPointF &mousePosition )
{
	currentPixelPoint = mousePosition;
	OpenGL::Math::dvec2 curr = renderer->convertWindowTo2D( mousePosition.x(), mousePosition.y(),true ) ;

	currentWorldPoint.setX( curr.x );	
	currentWorldPoint.setY( curr.y );
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onMouseMoved(){}
// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onMousePressed(){}
// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onMouseReleased(){}
// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onMouseDoubleClick(){}
// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onMouseWheel(){}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::mousePressEvent       ( QGraphicsSceneMouseEvent *e )
{
	// Propagate event to graphics items
	QGraphicsScene::mousePressEvent( e );

	if( e->isAccepted() )
		return;

	trackMousePosition( e->scenePos() );
	
	uim->updateMouse(e,true);
	updating = true;
	
	onMousePressed();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::mouseMoveEvent        ( QGraphicsSceneMouseEvent *e )
{
	// Propagate event to graphics items
	QGraphicsScene::mouseMoveEvent( e );

	if( e->isAccepted() )
		return;

	trackMousePosition( e->scenePos() );

	uim->updateMouse(e,false);

	onMouseMoved();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::mouseReleaseEvent     ( QGraphicsSceneMouseEvent *e )
{
	// Propagate event to graphics items
	QGraphicsScene::mouseReleaseEvent( e );

	if( e->isAccepted() )
		return;

	trackMousePosition( e->scenePos() );

	uim->updateMouse(e,true);
	updating = false;

	onMouseReleased();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::wheelEvent            ( QGraphicsSceneWheelEvent *e )
{
	QGraphicsScene::wheelEvent( e );
	if( e->isAccepted() )
		return;

	trackMousePosition( e->scenePos() );

	uim->updateMouse(e,true);

	onMouseWheel();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::mouseDoubleClickEvent ( QGraphicsSceneMouseEvent *e )
{
	QGraphicsScene::mouseDoubleClickEvent( e );

	if( e->isAccepted() )
		return;

	trackMousePosition( e->scenePos() );

	uim->updateMouse(e,true);

	onMouseDoubleClick();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::contextMenuEvent      ( QGraphicsSceneContextMenuEvent *e )
{}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::keyPressEvent ( QKeyEvent *e )
{
	QGraphicsScene::keyPressEvent(e);
	if( e->isAccepted() )
		return;

	uim->updateKeyboard(e,true);
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::keyReleaseEvent ( QKeyEvent *e )
{
	QGraphicsScene::keyReleaseEvent(e);
	if( e->isAccepted() )
		return;

	uim->updateKeyboard(e,false);
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::makeCurrent()
{
	static_cast<GLGraphicsView*>(view)->makeCurrent();
}